package me.flyray.bsin.server.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.UUID;

/**
 * 图片下载工具类
 * 支持从HTTP地址下载图片并转换为不同格式
 */
@Slf4j
@Component
public class ImageDownloadUtil {

    /**
     * 支持的图片格式
     */
    private static final String[] SUPPORTED_IMAGE_TYPES = {
            "image/jpeg", "image/jpg", "image/png", "image/gif", "image/bmp", "image/webp"
    };

    /**
     * 默认超时时间（毫秒）
     */
    private static final int DEFAULT_TIMEOUT = 30000;

    /**
     * 从HTTP地址下载图片并转换为InputStream
     *
     * @param imageUrl 图片URL地址
     * @return InputStream 图片输入流
     * @throws Exception 下载异常
     */
    public InputStream downloadImageAsInputStream(String imageUrl) throws Exception {
        return downloadImageAsInputStream(imageUrl, DEFAULT_TIMEOUT);
    }

    /**
     * 从HTTP地址下载图片并转换为InputStream（指定超时时间）
     *
     * @param imageUrl 图片URL地址
     * @param timeout  超时时间（毫秒）
     * @return InputStream 图片输入流
     * @throws Exception 下载异常
     */
    public InputStream downloadImageAsInputStream(String imageUrl, int timeout) throws Exception {
        log.info("开始下载图片，URL：{}", imageUrl);
        
        if (imageUrl == null || imageUrl.trim().isEmpty()) {
            throw new RuntimeException("图片URL不能为空");
        }
        
        HttpURLConnection connection = null;
        InputStream inputStream = null;
        
        try {
            // 创建URL连接
            URL url = new URL(imageUrl);
            connection = (HttpURLConnection) url.openConnection();
            
            // 设置连接参数
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(timeout);
            connection.setReadTimeout(timeout);
            connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
            connection.setRequestProperty("Accept", "image/*");
            connection.setDoInput(true);
            connection.setUseCaches(false);
            
            // 建立连接
            connection.connect();
            
            // 检查响应码
            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                throw new RuntimeException("图片下载失败，HTTP响应码：" + responseCode);
            }
            
            // 检查内容类型
            String contentType = connection.getContentType();
            if (!isValidImageType(contentType)) {
                log.warn("不支持的图片类型：{}", contentType);
            }
            
            // 获取输入流
            inputStream = connection.getInputStream();
            
            // 将输入流转换为字节数组，然后重新创建输入流（避免连接关闭后流失效）
            byte[] imageBytes = IOUtils.toByteArray(inputStream);
            log.info("图片下载成功，大小：{} bytes，类型：{}", imageBytes.length, contentType);
            
            return new ByteArrayInputStream(imageBytes);
            
        } catch (Exception e) {
            log.error("图片下载失败，URL：{}，错误：{}", imageUrl, e.getMessage(), e);
            throw new RuntimeException("图片下载失败：" + e.getMessage(), e);
        } finally {
            // 关闭资源
            closeQuietly(inputStream);
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    /**
     * 从HTTP地址下载图片并保存为临时文件
     *
     * @param imageUrl 图片URL地址
     * @return File 临时文件
     * @throws Exception 下载异常
     */
    public File downloadImageAsFile(String imageUrl) throws Exception {
        return downloadImageAsFile(imageUrl, DEFAULT_TIMEOUT);
    }

    /**
     * 从HTTP地址下载图片并保存为临时文件（指定超时时间）
     *
     * @param imageUrl 图片URL地址
     * @param timeout  超时时间（毫秒）
     * @return File 临时文件
     * @throws Exception 下载异常
     */
    public File downloadImageAsFile(String imageUrl, int timeout) throws Exception {
        log.info("开始下载图片到临时文件，URL：{}", imageUrl);
        
        InputStream inputStream = null;
        FileOutputStream outputStream = null;
        File tempFile = null;
        
        try {
            // 下载图片为输入流
            inputStream = downloadImageAsInputStream(imageUrl, timeout);
            
            // 创建临时文件
            String fileName = getFileNameFromUrl(imageUrl);
            if (fileName == null || fileName.isEmpty()) {
                fileName = "image_" + UUID.randomUUID().toString().replace("-", "") + ".jpg";
            }
            
            tempFile = File.createTempFile("download_", "_" + fileName);
            tempFile.deleteOnExit(); // 程序退出时自动删除
            
            // 写入文件
            outputStream = new FileOutputStream(tempFile);
            IOUtils.copy(inputStream, outputStream);
            
            log.info("图片下载到临时文件成功，文件路径：{}，大小：{} bytes", 
                    tempFile.getAbsolutePath(), tempFile.length());
            
            return tempFile;
            
        } catch (Exception e) {
            log.error("图片下载到临时文件失败，URL：{}，错误：{}", imageUrl, e.getMessage(), e);
            throw new RuntimeException("图片下载到临时文件失败：" + e.getMessage(), e);
        } finally {
            // 关闭资源
            closeQuietly(inputStream);
            closeQuietly(outputStream);
        }
    }

    /**
     * 从HTTP地址下载图片并转换为字节数组
     *
     * @param imageUrl 图片URL地址
     * @return byte[] 图片字节数组
     * @throws Exception 下载异常
     */
    public byte[] downloadImageAsBytes(String imageUrl) throws Exception {
        return downloadImageAsBytes(imageUrl, DEFAULT_TIMEOUT);
    }

    /**
     * 从HTTP地址下载图片并转换为字节数组（指定超时时间）
     *
     * @param imageUrl 图片URL地址
     * @param timeout  超时时间（毫秒）
     * @return byte[] 图片字节数组
     * @throws Exception 下载异常
     */
    public byte[] downloadImageAsBytes(String imageUrl, int timeout) throws Exception {
        log.info("开始下载图片为字节数组，URL：{}", imageUrl);
        
        InputStream inputStream = null;
        
        try {
            // 下载图片为输入流
            inputStream = downloadImageAsInputStream(imageUrl, timeout);
            
            // 转换为字节数组
            byte[] imageBytes = IOUtils.toByteArray(inputStream);
            
            log.info("图片下载为字节数组成功，大小：{} bytes", imageBytes.length);
            
            return imageBytes;
            
        } catch (Exception e) {
            log.error("图片下载为字节数组失败，URL：{}，错误：{}", imageUrl, e.getMessage(), e);
            throw new RuntimeException("图片下载为字节数组失败：" + e.getMessage(), e);
        } finally {
            closeQuietly(inputStream);
        }
    }

    /**
     * 检查是否为有效的图片类型
     *
     * @param contentType 内容类型
     * @return boolean 是否为有效图片类型
     */
    private boolean isValidImageType(String contentType) {
        if (contentType == null) {
            return false;
        }
        
        String lowerContentType = contentType.toLowerCase();
        for (String supportedType : SUPPORTED_IMAGE_TYPES) {
            if (lowerContentType.contains(supportedType)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 从URL中提取文件名
     *
     * @param imageUrl 图片URL
     * @return String 文件名
     */
    private String getFileNameFromUrl(String imageUrl) {
        try {
            URL url = new URL(imageUrl);
            String path = url.getPath();
            if (path != null && !path.isEmpty()) {
                int lastSlashIndex = path.lastIndexOf('/');
                if (lastSlashIndex >= 0 && lastSlashIndex < path.length() - 1) {
                    return path.substring(lastSlashIndex + 1);
                }
            }
        } catch (Exception e) {
            log.warn("从URL提取文件名失败：{}", e.getMessage());
        }
        return null;
    }

    /**
     * 获取图片文件扩展名
     *
     * @param imageUrl 图片URL
     * @return String 文件扩展名
     */
    public String getImageExtension(String imageUrl) {
        String fileName = getFileNameFromUrl(imageUrl);
        if (fileName != null && fileName.contains(".")) {
            return fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        }
        return "jpg"; // 默认扩展名
    }

    /**
     * 安全关闭资源
     *
     * @param closeable 可关闭的资源
     */
    private void closeQuietly(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                log.warn("关闭资源失败：{}", e.getMessage());
            }
        }
    }
} 